#include "../include.h"

#include <functional>
#include <thread>

#include <boost/asio/steady_timer.hpp>

#include "define.h"

#include "duration.h"
#include "asiowrap_iocontext.h"
#include "asiowrap_strand.h"

using namespace afcore;

class CAsioTestPrinter {
public:
  CAsioTestPrinter(afcore::asio::CIoContext& io)
    : strand_(io),
      timer1_(io, RSeconds(1)),
      timer2_(io, RSeconds(1)),
      count_(0) {
    timer1_.async_wait(boost::asio::bind_executor(strand_,
      std::bind(&CAsioTestPrinter::Print1, this)));

    timer2_.async_wait(boost::asio::bind_executor(strand_,
      std::bind(&CAsioTestPrinter::Print2, this)));
  }

  ~CAsioTestPrinter() {
    std::cout << "Final count is " << count_ << std::endl;
  }

  void Print1() {
    if (count_ < 10) {
      std::cout << "Timer 1: " << count_ << std::endl;
      ++count_;

      timer1_.expires_at(timer1_.expiry() + RSeconds(1));
      timer1_.async_wait(boost::asio::bind_executor(strand_,
        std::bind(&CAsioTestPrinter::Print1, this)));
    }
  }

  void Print2() {
    if (count_ < 10) {
      std::cout << "Timer 2: " << count_ << std::endl;
      ++count_;

      timer2_.expires_at(timer2_.expiry() + std::chrono::seconds(1));
      timer2_.async_wait(boost::asio::bind_executor(strand_,
        std::bind(&CAsioTestPrinter::Print2, this)));
    }
  }

private:
  afcore::asio::CStrand strand_;
  boost::asio::steady_timer timer1_;
  boost::asio::steady_timer timer2_;
  int count_;
};

TEST_CASE("Test asio", "[asio]") {
  using namespace afcore;

  afcore::asio::CIoContext io_context;
  CAsioTestPrinter p(io_context);
  std::thread t(std::bind(&afcore::asio::CIoContext::run, &io_context));
  io_context.run();
  t.join();
}